#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
生成器

"""
g = (x * x for x in range(1, 10))

for n in g:
    print(n)


def fib(max_num):
    num, a, b = 0, 0, 1
    while num < max_num:
        print(b)
        a, b = b, a + b
        num += 1
    return 'done'


fib(10)


# 仔细观察，可以看出，fib函数实际上是定义了斐波拉契数列的推算规则，可以从第一个元素开始，推算出后续任意的元素，这种逻辑其实非常类似generator。
# 也就是说，上面的函数和generator仅一步之遥。要把fib函数变成generator函数，只需要把print(b)改为yield b就可以了：


def fib2(max_num):
    num, a, b = 0, 0, 1
    while num < max_num:
        yield b
        a, b = b, a + b
        num += 1
    return 'done'


fib2(10)
print(fib2(10))

# generator函数和普通函数的执行流程不一样。普通函数是顺序执行，遇到return语句或者最后一行函数语句就返回。而变成generator的函数，在每次调用next()的时候执行，遇到yield语句返回，再次执行时从上次返回的yield语句处继续执行


def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield 3
    print('step 3')
    yield 5


o = odd()
print(next(o))
print(next(o))
print(next(o))

# 请务必注意：调用generator函数会创建一个generator对象，多次调用generator函数会创建多个相互独立的generator。
# 有的童鞋会发现这样调用next()每次都返回1
next(odd())
next(odd())
next(odd())
# 但是用for循环调用generator时，发现拿不到generator的return语句的返回值
for b in fib2(6):
    print('b:', b)

# 如果想要拿到返回值，必须捕获StopIteration错误，返回值包含在StopIteration的value中
g = fib2(6)
while True:
    try:
        x = next(g)
        print('g:', x)
    except StopIteration as e:
        print('Generator return value:', e.value)
        break


